﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace GenerateurTrajectoire
{
    public partial class frmMain : Form
    {
        public frmMain()
        {
            InitializeComponent();


            if (fichier == null)
            {
                fichier = new Dossier();
                fichier.id = -1;
            }

            if (fichier.trajectoires != null)
            {
                foreach (Trajectoire t in fichier.trajectoires)
                {
                    if (t.id > maxId)
                        maxId = t.id;
                    TreeNode noeud = new TreeNode(t.nom, 1, 1);
                    noeud.Tag = t.id;

                    tree.Nodes[0].Nodes.Add(noeud);
                    tree.Nodes[0].Expand();
                }
            }
            changed = false;
            txtNom.Focus();
        }
        private Trajectoire curTrajectoire = null;
        private Dossier fichier = Dossier.Get("Save.xml");
        private int maxId = 1;
        bool changed = false;

        private static Brush brBlack = new SolidBrush(Color.FromArgb(200, Color.Black));
        private static Brush brGreen = new SolidBrush(Color.FromArgb(200, Color.DarkGreen));
        private static Pen pen = new Pen(brGreen, 4);
        private static Pen penBig = new Pen(brGreen, 67);
        private static Brush brRed = new SolidBrush(Color.FromArgb(200, Color.DarkRed));
        private static Pen penRed = new Pen(brRed, 4);
        private static Pen penRedBig = new Pen(brRed, 67);
        private static Font font = new Font(FontFamily.GenericSansSerif, 12);
        List<Objectif> lst = new List<Objectif>();
        private void imgPlan_Paint(object sender, PaintEventArgs e)
        {
            Pen pe = null;
            Objectif last = new Objectif() { X = int.MaxValue, Y = int.MaxValue };
            foreach (Objectif p in lst)
            {
                if (p.enAvant && chkRobot.Checked)
                    pe = penBig;
                else if (!p.enAvant && chkRobot.Checked)
                    pe = penRedBig;
                else if (!p.enAvant)
                    pe = penRed;
                else
                    pe = pen;

                if (last.X != int.MaxValue)
                    e.Graphics.DrawLine(pe, new Point(last.X, last.Y), new Point(p.X, p.Y));
                e.Graphics.FillEllipse(brGreen, p.X - 10, p.Y - 10, 20, 20);
                if (last.X != int.MaxValue)
                    e.Graphics.FillEllipse(brGreen, last.X - 10, last.Y - 10, 20, 20);

                last = p;
            }


        }


        private Objectif Update(Objectif o)
            {
                if(o.index<0)
                {
            try
            {
                o = GetObjectif(Convert.ToInt32(txtX.Text), Convert.ToInt32(txtY.Text), true, -1);
            }
            catch { }}
                else{
                try
                {
                    o = GetObjectif(Convert.ToInt32(grid.Rows[o.index].Cells[0].Value), Convert.ToInt32(grid.Rows[o.index].Cells[1].Value), o.enAvant, o.index);
                }
                catch { }}

                return o;
        }

        private List<Objectif> GetListPoints()
        {
            List<Objectif> lst = new List<Objectif>();
            try
            {
                lst.Add(GetObjectif(Convert.ToInt32(txtX.Text), Convert.ToInt32(txtY.Text), true, -1));
            }
            catch { }

            foreach (DataGridViewRow r in grid.Rows)
            {
                try
                {
                    if (r.Cells[0].Value.ToString().Length > 0 && r.Cells[1].Value.ToString().Length > 0)
                        lst.Add(GetObjectif(Convert.ToInt32(r.Cells[0].Value), Convert.ToInt32(r.Cells[1].Value), Convert.ToBoolean(r.Cells[2].Value), r.Index));
                }
                catch { }
            }

            return lst;
        }

        private Objectif GetObjectif(int X, int Y, bool avant, int index)
        {
            return new Objectif() { X = 140 + X * 670 / 3000, Y = 97 + Y * 670 / 3000, enAvant = avant, XRobot = X, YRobot = Y, index = index };
        }

        private void grid_CellEndEdit(object sender, EventArgs e)
        {
            if (grid.Rows.Count > 1)
            {
                RefreshAll(true);
                changed = true;
            }
        }

        private void RefreshAll(bool withCode)
        {
            lst = GetListPoints();
            imgPlan.Refresh();
            if (withCode)
            {
                StringBuilder code = new StringBuilder();
                foreach (Objectif p in lst)
                {
                    try
                    {
                        code.AppendFormat(txtTemplate.Text, p.XRobot, p.YRobot, p.enAvant.ToString().ToLower()).AppendLine();
                    }
                    catch { }
                }
                txtCode.Text = code.ToString();
            }
        }



        private void chkRobot_CheckedChanged(object sender, EventArgs e)
        {
            RefreshAll(true);
        }

        Objectif curObj = null;
        Objectif curObjR = null;
        private void imgPlan_MouseMove(object sender, MouseEventArgs e)
        {
            if (curObj != null)
            {
                Point p = new Point((e.X - 140) * 3000 / 670, (e.Y - 97) * 3000 / 670);
                if (curObj.index < 0)
                {
                    txtX.Text = p.X.ToString();
                    txtY.Text = p.Y.ToString();
                    txtX.Refresh();
                    txtY.Refresh();

                }
                else
                {
                    grid.Rows[curObj.index].Cells[0].Value = p.X;
                    grid.Rows[curObj.index].Cells[1].Value = p.Y;
                    grid.Refresh();
                }

                tpInfo.SetToolTip(imgPlan, Update(curObj).ToString());
                RefreshAll(false);
            }
            else
            {
                Objectif o = GetObj(e.X, e.Y, true);
                if (o == null)
                    o = IsOnLine(new Point(e.X, e.Y), false);
                if (o == null)
                {
                    curObjInfo = null;
                    tpInfo.RemoveAll();
                    imgPlan.Cursor = Cursors.Default;
                }
                else if(o!= curObjInfo)
                {
                    curObjInfo = o;
                    tpInfo.SetToolTip(imgPlan, o.ToString());
                    imgPlan.Cursor = Cursors.Hand;
                }
            }
        }
        Objectif curObjInfo = null;


        private void imgPlan_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left && chkActive.Checked)
            {
                curObj = GetObj(e.X, e.Y, false);
                if (curObj != null)
                {
                    foreach (DataGridViewRow r in grid.Rows)
                        r.Selected = false;
                    if (curObj.index >= 0)
                        grid.Rows[curObj.index].Selected = true;
                    tpInfo.SetToolTip(imgPlan, Update(curObj).ToString());
                }
                imgPlan.Cursor = Cursors.Hand;
                RefreshAll(false);
                changed = true;
            }
            else if (e.Button == System.Windows.Forms.MouseButtons.Right && chkActive.Checked)
                curObjR = GetObj(e.X, e.Y, true);

        }

        private Objectif GetObj(int x, int y, bool allowNull)
        {
            Objectif o = lst.Find(ob => ob.X + 10 > x && ob.X - 10 < x && ob.Y + 10 > y && ob.Y - 10 < y);
            if (o == null && !allowNull)
            {
                o = IsOnLine(new Point(x, y), true);
                if (o == null)
                {
                    // nouveau point
                    Point p = new Point((x - 140) * 3000 / 670, (y - 97) * 3000 / 670);
                    if (txtX.Text.Length == 0 || txtY.Text.Length == 0)
                    {
                        txtX.Text = p.X.ToString();
                        txtY.Text = p.Y.ToString();
                    }
                    else
                    {
                        grid.Rows.Add(p.X, p.Y, true);
                    }
                    lst = GetListPoints();

                    o = lst.Find(ob => ob.X + 5 > x && ob.X - 5 < x && ob.Y + 5 > y && ob.Y - 5 < y);
                }
            }

            return o;
        }

        private Objectif IsOnLine(Point p, bool withCreate)
        {
            Objectif prevObj = null;

            foreach (Objectif o in lst)
            {
                if (prevObj != null && IsPointSurSegment(prevObj, o, p))
                {
                    if (withCreate)
                    {
                        Point pp = new Point((p.X - 140) * 3000 / 670, (p.Y - 97) * 3000 / 670);
                        grid.Rows.Insert(o.index, pp.X,pp.Y,true);
                        lst = GetListPoints();
                        return lst.Find(ob => ob.X + 5 > p.X && ob.X - 5 < p.X && ob.Y + 5 > p.Y && ob.Y - 5 < p.Y);
                    }
                    return prevObj;
                }
                prevObj = o;
            }
            return null;
        }
        private bool IsPointSurSegment(Objectif A, Objectif B, Point p)
        {
            // point dans le rectangle
            if (p.X < Math.Min(A.X, B.X) || p.X > Math.Max(A.X, B.X)
                || p.Y < Math.Min(A.Y, B.Y) || p.Y > Math.Max(A.Y, B.Y))
                return false;

            double d = Math.Abs((B.X - A.X) * (A.Y - p.Y) - (A.X - p.X) * (B.Y - A.Y)) / Math.Sqrt(Math.Pow((B.X - A.X), 2) + Math.Pow((B.Y - A.Y), 2));

            return d < 5;
        }


        private void imgPlan_MouseUp(object sender, MouseEventArgs e)
        {
            curObj = null;
            RefreshAll(true);
            txtCode.Refresh();
        }

        private void imgPlan_MouseHover(object sender, EventArgs e)
        {
        }

        private void grid_KeyUp(object sender, KeyEventArgs e)
        {
            RefreshAll(true);
            changed = true;
        }

        private void supprimerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            grid.Rows.RemoveAt(curObjR.index);
            RefreshAll(true);
            changed = true;
        }

        private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
        {
            if (curObjR == null || curObjR.index < 0)
                e.Cancel = true;
        }

        private void txtRobot_TextChanged(object sender, EventArgs e)
        {
            try
            {
                penBig = new Pen(brGreen, Convert.ToInt32(txtRobot.Text) *670/3000);
                penRedBig = new Pen(brRed, Convert.ToInt32(txtRobot.Text) * 670 / 3000);
            }
            catch { }
            RefreshAll(false);
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            Sauver();
            changed = false;
        }

        private void Sauver()
        {
            if (curTrajectoire == null)
            {
                curTrajectoire = new Trajectoire();
                if (fichier.trajectoires == null)
                {
                    fichier.trajectoires = new List<Trajectoire>();
                }
                fichier.trajectoires.Add(curTrajectoire);
                TreeNode noeud = new TreeNode(txtNom.Text, 1, 1);
                maxId++;
                noeud.Tag = maxId;
                curTrajectoire.id = maxId;
                if (tree.SelectedNode != null && (tree.SelectedNode.Tag as int? ?? -1) < 0)
                {
                    tree.SelectedNode.Nodes.Add(noeud);
                    tree.SelectedNode.Expand();
                }
                else
                {
                    tree.Nodes[0].Nodes.Add(noeud);
                    tree.Nodes[0].Expand();
                }
                tree.SelectedNode = noeud;
            }
            else
            {
                tree.SelectedNode.Text = txtNom.Text;
            }
            curTrajectoire.ojectifs = GetListPoints();
            curTrajectoire.nom = txtNom.Text;

            fichier.Save("Save.xml");
        }

        private void btnNew_Click(object sender, EventArgs e)
        {
            if (changed && MessageBox.Show("Voulez-vous sauvegarder ?", "Sauver", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
                Sauver();

            curTrajectoire = null;

            grid.Rows.Clear();
            txtX.Text = "";
            txtY.Text = "";
            txtNom.Text = "";
            changed = false;
            RefreshAll(true);
        }


        private void Load(Trajectoire traj)
        {
            txtNom.Text = traj.nom;
            grid.Rows.Clear();
            foreach (Objectif o in traj.ojectifs)
            {
                if (o.index == -1)
                {
                    txtX.Text = o.XRobot.ToString();
                    txtY.Text = o.YRobot.ToString();
                }
                else
                {
                    grid.Rows.Add(o.XRobot, o.YRobot, o.enAvant);
                }
            }

            curTrajectoire = traj;
            changed = false;
            RefreshAll(true);
        }

        private void tree_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (changed && MessageBox.Show("Voulez-vous sauvegarder ?", "Sauver", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
                Sauver();
            if (fichier.trajectoires != null)
            {
                foreach (Trajectoire t in fichier.trajectoires)
                    if (e.Node.Tag as int? == t.id)
                        Load(t);
            }
        }

        private void btnDel_Click(object sender, EventArgs e)
        {
            if (tree.SelectedNode != null && tree.SelectedNode.Tag as int? != -1 &&
                MessageBox.Show("Voulez-vous le supprimer ?", "Suppression", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
            {
                if (tree.SelectedNode.Tag as int? > 0)
                {
                    for(int i = 0;i<fichier.trajectoires.Count;i++)
                        if (fichier.trajectoires[i].id == tree.SelectedNode.Tag as int?)
                        {
                            fichier.trajectoires.RemoveAt(i);
                        }
                    fichier.Save("Save.xml");
                }
                tree.SelectedNode.Parent.Nodes.Remove(tree.SelectedNode);
            }
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            if (tree.SelectedNode != null)
            {
                frmInput frm = new frmInput();
                frm.ShowDialog();
                if (frm.DialogResult == System.Windows.Forms.DialogResult.OK)
                {
                    TreeNode noeud = new TreeNode(frm.value);
                    maxId++;
                    noeud.Tag = -maxId;
                    if ((tree.SelectedNode.Tag as int? ?? 0) > 0)
                    {
                        tree.SelectedNode.Parent.Nodes.Add(noeud);
                        Dossier parent = FindDossier(fichier, (tree.SelectedNode.Parent.Tag as int? ?? 0));
                        parent.dossiers.Add(new Dossier() { id = -maxId, nom = noeud.Text });
                    }
                    else
                    {
                        tree.SelectedNode.Nodes.Add(noeud);
                        Dossier parent = FindDossier(fichier, (tree.SelectedNode.Tag as int? ?? 0));
                        parent.dossiers.Add(new Dossier() { id = -maxId, nom = noeud.Text });
                    }
                }
            }
        }

        private Dossier FindDossier(Dossier d, int id)
        {
            if (d.id == id)
                return d;
            if (d == null) 
                return null;
            foreach (Dossier dd in d.dossiers)
            {
                Dossier val = FindDossier(dd, id);
                if (val != null)
                    return val;
            }
            return null;
        }


    }
}
